/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package controller;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.Serializable;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import model.Conference;
import model.User;
import view.*;
import de.javasoft.plaf.synthetica.SyntheticaWhiteVisionLookAndFeel;
import java.awt.HeadlessException;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.rmi.AccessException;
import java.text.ParseException;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
/**
 *
 * @author mona
 */
public class ClientImpl extends UnicastRemoteObject implements ClientInt,Serializable
{
    
    Map<String,ChatWindow> chatWindow = new HashMap<>();
    Map<Integer,ChatWindow> chatConference = new HashMap<>();
    ProgressBar fileProgressbar;
    AddFriend addFriend ;
    ContactList contactList ;
    AddPeople addPeople ;
    SignIn signIn ;
    SignUp signUp ;
    SendMail sendMail ;
    FileUpload file;
    
    XMLHandler xmlHandler ;
    ChatServerInt server;
    Map<String,ClientInt> allclients=new HashMap<>();
    Map<Integer,Conference> conference = new HashMap<>();
    
    User[] friends;
    User myUser;
    
    String f;
    String path;
    BufferedInputStream in;
    BufferedOutputStream out;
    FileDownload fd;
    Thread th;    
    
    public static void main(String[] args)
    { 
        try { 
            UIManager.setLookAndFeel(new SyntheticaWhiteVisionLookAndFeel());
            ClientImpl run = new ClientImpl();
            
        } catch (NotBoundException | RemoteException ex) {
            System.out.println("Can't Connect to the Server!!");
        } catch (ParseException | UnsupportedLookAndFeelException ex) {
            System.out.println("Can't Load Look and Feel!!");
        }
    }
    
    public ClientImpl() throws RemoteException, NotBoundException{
                    
            signIn = new SignIn();
       
            signIn.addSignInListener(new SignInListener());
            signIn.addSignUpListener(new AddSignUpListener());
            signIn.setVisible(true);
            
            Runtime.getRuntime().addShutdownHook(new Thread()
            {
                @Override
                public void run()
                {
                    logoutFn();
                }
            });
    }
    
    public static int mapStatusToInt(String status){
            int statusInt = 0;
            switch (status){
                case "Online": statusInt = 1; break; 
                case "Busy": statusInt = 2; break;
                case "Away": statusInt = 3; break;    
                case "Invisible": statusInt = 4; break;
            }
            return statusInt;
    }
    
    public static String mapStatusToString(int status){
        String statusStr = "Offline";
            switch (status){
                case 1:             
                    statusStr = "Online"; break; 
                case 2:        
                    statusStr = "Busy"; break;
                case 3:        
                    statusStr = "Away"; break;    
                case 4:   
                    statusStr = "Offline"; break;
            }
            return statusStr;
    }
    
    private User getUserObj(String userName){
        User friend = null;
        if(friends != null){
            for (int i = 0; i < friends.length; i++) {
                if(friends[i].getUserName().equals(userName)){
                    friend = friends[i];
                    break;
                }
            }    
        }
            
         return friend;
    }
    
    private User[] getUsersObjs(String[] userNames){
        User[] confFriends = new User[userNames.length];
       // System.out.println("getUsersObjs fn "+userNames.length);
        for (int i = 0; i < userNames.length; i++) {
            for (User friend : friends) {
                if (friend.getUserName().equals(userNames[i])) {
                    confFriends[i] = friend;
                }else if(myUser.getUserName().equals(userNames[i])){
                    confFriends[i] = myUser;
                }else{
                    confFriends[i] = new User(userNames[i], "", 0);
                }   
            }
        }
        return confFriends;
    }
    
    
    @Override
    public void receive(String friendUserName , String msg) throws RemoteException{
        if(!allclients.containsKey(friendUserName)){     
            
            ChatWindow cw = new ChatWindow(getUserObj(friendUserName),myUser.getUserName());
           // cw.addAddPeopleListener(new AddPeopleListener());
            cw.addSendMsgListener(new SendMsgListener());
            cw.addOpenSendMailListener(new OpenSendMailListener());
            cw.sendFileListener(new SendFileListener());
            cw.addCloseWindowListener(new CloseChatWindowListener());
            cw.addInteractiveChatListener(new AddInteractiveChatListener());
            chatWindow.put(friendUserName, cw);
            
            ClientInt friendClient = server.returnUsers(friendUserName);
            allclients.put(friendUserName, friendClient);

            
            cw.setVisible(true);
        }else if(!chatWindow.get(friendUserName).isVisible())
            chatWindow.get(friendUserName).setVisible(true);
        
            chatWindow.get(friendUserName).sendMsg(friendUserName,msg);
        
            xmlHandler = new XMLHandler(friendUserName);
            xmlHandler.saveChat(friendUserName,myUser.getUserName(),msg);
        }
    
    @Override
    public void receiveToConference(Integer confID , String friendUserName ,String msg) throws RemoteException{
        if(chatConference.containsKey(confID)){
            chatConference.get(confID).sendMsg(friendUserName, msg);
        }
    }
    
    @Override
    public void startConference(String[] usersnames,ClientInt[] users , int confId) throws RemoteException{

        ChatWindow cw = new ChatWindow(getUsersObjs(usersnames),confId,myUser.getUserName());
        //cw.addAddPeopleListener(new AddPeopleListener());
        cw.addSendMsgListener(new SendMsgListener());
        cw.sendFileListener(new SendFileListener());
        cw.addCloseWindowListener(new CloseChatWindowListener());    
        chatConference.put(confId, cw);
        cw.setVisible(true);
        Conference cf = new Conference(users);
        
        conference.put(confId, cf);
        if(addPeople!=null)
            addPeople.setVisible(false);
    }

    /**
     *
     * @param userName
     * @param status
     * @throws RemoteException
     */
    @Override
    public void updateFriendStatus(String userName , int status) throws RemoteException{
        User obj = getUserObj(userName);
        obj.status(status);
        
        if((status == 0 || status == 4) && allclients.containsKey(userName))
            allclients.remove(userName);      
        
        contactList.updateFriendStatus(userName,ClientImpl.mapStatusToString(status) );
    }
    
    public String getMyUserName() throws RemoteException{
        return myUser.getUserName();
    }
    
    public String getMyEmail() {
        return myUser.email();
    }
    
    @Override
    public void checkFriendReqs() throws RemoteException{
     
            Thread t = new Thread(new Runnable(){
                public void run(){
                    try {
                        User[] friendReqs = server.getFriends(signIn.getUsername(), signIn.getPassword(),0);
                        Vector<User> added = new Vector<>();
                        if(friendReqs != null){
                            for (User user : friendReqs) {
                                int reply = JOptionPane.showConfirmDialog(null,"Do you to add Friend : "+user.getUserName(),"",JOptionPane.YES_NO_OPTION);
                                if(reply == JOptionPane.YES_OPTION){
                                    added.add(user);
                                    contactList.addFriend(user);
                                    System.out.println(mapStatusToString(user.status()) + user.status());
                                    server.controlFriendRelation(user.getUserName(),myUser.getUserName(), 1);
                                }else{
                                    server.controlFriendRelation(user.getUserName(),myUser.getUserName(), -1);
                                }
                            }
                            
                            int size = 0;
                            if(friends != null)
                                size = friends.length;
                            
                            User[] friendsTemp = new User[size+added.size()];
                            
                            for (int i = 0 ; i < friendsTemp.length ; i++ ) {
                                if(i < size)
                                    friendsTemp[i] = friends[i];
                                else
                                    friendsTemp[i] = added.get( size - i );
                            }
                            
                            friends = friendsTemp;
                        }   
                    } catch (RemoteException ex) {
                            System.out.println("Can't Connect to the server");
                    }
                
                }
            });
            t.start();
    }
    
    @Override
    public void friendReqAccepted(User newFriend) throws RemoteException{
        if(friends == null){
            friends = new User[1];
            friends[0] = newFriend;
        }else{
            User[] friendsTemp = new User[friends.length + 1];
                
            for (int i = 0 ; i < friends.length ; i++ ) {
                friendsTemp[i] = friends[i];
            }
                
            friendsTemp[friends.length] = newFriend;
                
            friends = friendsTemp;
        }
        
        contactList.addFriend(newFriend);
        //System.out.println(newFriend.status());
    }
    
    /* */
   
    class AddUserListener implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent e) {
            String name = signUp.getNameUser();
            String password=signUp.getPasswordUser();
            String retype = signUp.getRetypeUser();
            String email=signUp.getEmail();
            String country = signUp.getCountry();
            String userName=signUp.getUserName();
            String gender = signUp.getGender();
            
            if(password.equals("0"))
            {
                JOptionPane.showMessageDialog(null,"Password should not contain any special characters");
            }
            if(gender==null)
            {
                JOptionPane.showMessageDialog(null, "Please Select gender");
            }
            if (password.isEmpty()) {
                JOptionPane.showMessageDialog(null, "Password Shouldn't be empty");
            }
            if (!email.matches("^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$")) {
                JOptionPane.showMessageDialog(null, "Email Should be Valid ");
            }
            if (!name.matches("^[\\p{L} .'-]+$")) {
                JOptionPane.showMessageDialog(null, "Name should be alphabetic ");
            }
            if (!userName.matches("^[\\p{L} .'-]+$")) {
                JOptionPane.showMessageDialog(null, "UserName should be alphabetic ");
            }
            if(! password.equals(retype))
            {
                JOptionPane.showMessageDialog(null,"Password and retype should be the Same");
            }
            if(!name.matches("^[\\p{L} .'-]+$"))
            {
               JOptionPane.showMessageDialog(null,"Name should be alphabetic ");
            }
            
            if(name.matches("^[\\p{L} .'-]+$")&&password.equals(retype)&& email.matches("^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$")&& !password.equals("0")
                    && gender!=null &&userName.matches("^[\\p{L} .'-]+$"))
            {
                try {
                    Registry reg = LocateRegistry.getRegistry("10.145.79.98",5010);
                    server =(ChatServerInt) reg.lookup("HelloService");

                    int adding= server.signUp(email, name, password, userName, country, gender);
                    //System.out.println(adding);
                    if(adding ==1 )
                    {
                        JOptionPane.showMessageDialog(null, "Done!");
                        System.out.println("Succeed");
                    }
                    else
                    {
                        JOptionPane.showMessageDialog(null, "Sorry be Sure that Email and UserName is Unique");
                        System.out.println("Failed");
                    }
                } catch (RemoteException ex) {
                    System.out.println("Can't connect to the server");
                    //ex.printStackTrace();
                } catch (NotBoundException ex) {
                    Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            
            
        }
        
    }
    
    class CloseChatWindowListener extends WindowAdapter
    {
        @Override
        public void windowClosing(WindowEvent e)
        {
            ChatWindow cw = (ChatWindow) SwingUtilities.getRoot((Component) e.getSource());
            if(chatWindow.containsKey(cw.getFriendUserName()))
                chatWindow.remove(cw.getFriendUserName());
            
            if(((Map)chatConference).containsKey(cw.getFriendUserName())) 
            {
                 ((Map)chatConference).remove(cw.getFriendUserName());
            }
            
            if(allclients.containsKey(cw.getFriendUserName()))
                allclients.remove(cw.getFriendUserName());
            
        }        
    }
        
    class AddSignUpListener extends MouseAdapter
    {

        @Override
        public void mouseClicked(MouseEvent e) {
           signUp= new SignUp();
           signUp.setVisible(true);
           signUp.addUserListener(new AddUserListener());
        }       
    }
    
    class SignInListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            
            try{
                // 

                Registry reg = LocateRegistry.getRegistry("10.145.79.98",5010);
                server =(ChatServerInt) reg.lookup("HelloService");

                if(signIn.getPassword().equals("0"))
                {
                    JOptionPane.showMessageDialog(null, "Password should be at least 5 characters and not include special characters");
                }
                else
                {

                int result = server.signIn(signIn.getUsername() ,signIn.getPassword(), ClientImpl.this);
                if(result == 1){
                    friends = server.getFriends(signIn.getUsername(), signIn.getPassword(),1);
                    
                    myUser = server.getMyUser(signIn.getUsername());
                    
                    contactList = new ContactList(friends,new StartChatListener(),myUser.getUserName());
                    //contactList.addStartChatListener(new StartChatListener());
                    contactList.setVisible(true);
                    contactList.addStartConferenceListener(new AddPeopleListener());
                    contactList.addChangeStatusListener(new ChangeStatusListener());
                    contactList.addLogOutListener(new LogOutListener());
                    contactList.addAddFriendListener(new AddFriendListener());
                    contactList.addCloseWindowListener(new WindowAdapter(){
                        @Override
                        public void windowClosing(WindowEvent e)
                        {
                            try {
                                ClientImpl.this.server.signOut(ClientImpl.this.myUser.getUserName());
                            } catch (RemoteException ex) {
                                System.out.println("Can't Connect to the server");
                            }
                        }
                    });
                    signIn.setVisible(false);
                    checkFriendReqs();                    
                }else
                    JOptionPane.showMessageDialog(signIn, "Please Sure to enter a valid email and password");
                }                  
            }catch(HeadlessException | RemoteException  | NotBoundException ex ){
                JOptionPane.showMessageDialog(null, "Can't Connect to the server...Please try again later");
                System.out.println("Can't Connect to Server");
                ex.printStackTrace();
            } 
        }
    }
    
    public void logoutFn(){
        try {
            
                if(server != null ) server.signOut(myUser.getUserName());

                if(contactList != null){    contactList.setVisible(false); contactList = null; }
                if(addFriend != null){      addFriend.setVisible(false);     addFriend = null;     }
                if(addPeople != null){      addPeople.setVisible(false);   addPeople = null;   }
                if(signIn != null){         signIn.setVisible(true);      }
                if(signUp != null){         signUp.setVisible(false);      signUp = null;      }
                if(sendMail != null){       sendMail.setVisible(false);    sendMail = null;    }
            
                for (Map.Entry<String, ChatWindow> entry : chatWindow.entrySet()) {
                    entry.getValue().setVisible(false);
                }
                chatWindow.clear();
            
                for (Map.Entry<Integer, ChatWindow> entry : chatConference.entrySet()) {
                    entry.getValue().setVisible(false);
                }
                chatConference.clear();
                        
            
                allclients.clear();
                conference.clear();
                myUser = null;
                friends = null;
                server = null;
                System.gc();
            
            } catch (RemoteException ex) {
                System.out.println("Can't connect to the server");
            }
    }
    
    class LogOutListener extends MouseAdapter
    {
        @Override
        public void mouseClicked(MouseEvent ae) {
            logoutFn();
        }
        
    }
    
    class ChangeStatusListener implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent ae) {            
            try {
                String status = contactList.getSelectedStatus();
                server.updateStatus(myUser.getUserName(),ClientImpl.mapStatusToInt(status) );              
            } catch (RemoteException ex) {
                System.out.println("Can't connect to the server");
            }
             
        }
        
    }
    
    class AddFriendListener extends MouseAdapter
    {
        @Override
        public void mouseClicked(MouseEvent ae) {            
            addFriend = new AddFriend();
            addFriend.setVisible(true);
            addFriend.addAddFriendListner(new AddFriendReqListener());
        }        
    }
    
    class AddFriendReqListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent ae) {            
            try {
                
                if(!server.addFriendBefore(myUser.getUserName(), addFriend.getFriendUserName())){
                    addFriend.setVisible(false);
                    int result = server.controlFriendRelation(myUser.getUserName(), addFriend.getFriendUserName(), 0);
                
                    if(result == 0){
                        JOptionPane.showMessageDialog(addFriend, "Error .. Please Try Again Later");
                    }

                }else{
                    JOptionPane.showMessageDialog(addFriend, "Added Before");
                }
                                
            } catch (RemoteException ex) {
                System.out.println("Can't Connect to the Server");
            }
        }        
    }
    
    class RemoveListListener implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent e) {
            //System.out.println("Hey");
           String item = addPeople.getRemoveSelected();
           int itemSel = addPeople.returnRemoveSelected();
           if(itemSel != -1 ){
                addPeople.removeListSelected(itemSel);
                addPeople.addList1ItemSelected(item);
           }
        }
        
    }
    class AddListListener implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent ae) {
            String item = addPeople.getSelected(); 
            int itemSel = addPeople.returnSelected();
            if(itemSel != -1){
                System.out.println(item);
                addPeople.removeItemSelected(itemSel);
                addPeople.addItemSelected(item);
            }
        }
        
    }
    class AddPeopleListener extends MouseAdapter
    {
        @Override
        public void mouseClicked(MouseEvent e) {
             
            addPeople = new AddPeople(friends);
            addPeople.setVisible(true);
            addPeople.addListListener(new AddListListener());
            addPeople.addDoneListener(new OpenConferenceListener());
            addPeople.removeListListener(new RemoveListListener());
       
        }
        
    }

    class OpenSendMailListener extends MouseAdapter
    {
        @Override
        public void mouseClicked(MouseEvent e) {            
            
            ChatWindow cw = (ChatWindow) SwingUtilities.getRoot((Component) e.getSource());
            sendMail = new SendMail();
            String[] emails = new String[1];
            emails[0] = cw.getFriendEmail();
            sendMail.setToEmail(emails);
            sendMail.setVisible(true);
           
            sendMail.addSendMailListener(new SendMailListener());
            
        }
        
    }

    class SendMailListener implements ActionListener
    {
        @Override
        public void actionPerformed(ActionEvent e) {
            try {
                //ChatWindow cw = (ChatWindow) SwingUtilities.getRoot((Component) e.getSource());
                
                //String usersName;
                
                //sendMail = new SendMail();
                sendMail.setVisible(false);
                server.sendMail(myUser.email(),sendMail.getEmails(), sendMail.getTitle(), sendMail.getMsg());
                
                //addPeople.addDoneListener(new OpenConferenceListener());
            } catch (RemoteException ex) {
                System.out.println("Can't connect to the server");
              //Logger.getLogger(ClientImpl.class.getName()).log(Level.SEVERE, null, ex);
            }
            
        }
        
    }
    
    class StartChatListener extends MouseAdapter {
        @Override
        public void mouseClicked(MouseEvent e) {            
            
            if (e.getClickCount() < 2) return;            
            String userName= contactList.getSelectedUser().getUserName();
            //System.out.println(userName);
            User user = contactList.getSelectedUser(); 
            if(user.status() == 0 || user.status() == 4 ){
                JOptionPane.showMessageDialog(null, "Sorry But your Friend Status is Offline Now");  
                return;
            }  
            
            if(chatWindow.containsKey(userName) && chatWindow.get(userName).isVisible() ){
                chatWindow.get(userName).toFront();
                return;
            }
            
            //System.out.println(userName+" here");
            ChatWindow cw = new ChatWindow(getUserObj(userName),myUser.getUserName());
            cw.setVisible(true);
            try {
                ClientInt userRef=server.returnUsers(userName);
               // System.out.println(userRef);
                allclients.put(userName, userRef);
                
            } catch (RemoteException ex) {
                System.out.println("Can't connect to the server");
                //Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
            }
            chatWindow.put(userName, cw);
            //cw.addAddPeopleListener(new AddPeopleListener());
            cw.sendFileListener(new SendFileListener());
            cw.addCloseWindowListener(new CloseChatWindowListener());
            cw.addSendMsgListener(new SendMsgListener());
            cw.addOpenSendMailListener(new OpenSendMailListener());
            cw.addInteractiveChatListener(new AddInteractiveChatListener());
        }   
    }  
    
    class OpenConferenceListener implements ActionListener{
        @Override
        public void actionPerformed(ActionEvent e) {
            String[] userNames = addPeople.getAddedUsersToConf();
            
            if(userNames != null){
                try {
                
                    server.startConference(userNames, chatConference.size(), myUser.getUserName());
                
                } catch (RemoteException ex) {
                    System.out.println("Can't open the conference");
                }
            }else{
                JOptionPane.showMessageDialog(addPeople, "No Friends Added");
            }
            
        }   
    } 
    
    
    class SendMsgListener implements ActionListener{
        @Override
        public void actionPerformed(ActionEvent e) {
            ChatWindow cw = (ChatWindow) SwingUtilities.getRoot((Component) e.getSource());
            try
            {
                if(cw.isConference()){
                    int confId = cw.getConfId();
                    int size = conference.get(confId).getSize();
                    String msg = cw.getMsgToSend();
                    for(int i = 0 ; i <size;i++){

                        conference.get(confId).getClientAt(i).receiveToConference(confId, myUser.getUserName(),msg );
                    }
                    //cw.sendMsg(myUsername, cw.getMsgToSend());
                
                }else{                
                    String msg = cw.getMsgToSend();
                    String friend = cw.getFriendUserName();
                    User friendObj = ClientImpl.this.getUserObj(friend);
                    if(friendObj.status() == 0 || friendObj.status() == 4 ){
                        JOptionPane.showMessageDialog(null, "Your Friend Is Offline Now !!");
                        return;
                    }
                    
                    if(!allclients.containsKey(cw.getFriendUserName()))
                    {
                        ClientInt userRef=server.returnUsers(cw.getFriendUserName());
                        allclients.put(cw.getFriendUserName(), userRef);
                    }
                    
                    allclients.get(cw.getFriendUserName()).receive(myUser.getUserName(),msg);
                    cw.sendMsg(myUser.getUserName(), msg);
                    
                    xmlHandler = new XMLHandler(cw.getFriendUserName());
                    xmlHandler.saveChat(myUser.getUserName(),cw.getFriendUserName(),msg);
                    
                }  
                
            }catch(RemoteException ex){                
                System.out.println("Can’t send msg to client!");
                // ex.printStackTrace();               
            }                
            System.out.println("Messge received: "+cw.getMsgToSend());
            
        }   
    }
    
    @Override
    public boolean startStream(String fileName,int fileSize,String friendName) throws RemoteException {
        
        if(out != null){
            JOptionPane.showMessageDialog(null, "Wait Until the current downloading operation finished");
            return false;
        }
        int exeIndex = fileName.lastIndexOf(".");
        int pathLength = fileName.length();
        String exe=fileName.substring(exeIndex,pathLength);
        
        int flag = receiveFile(fileName,friendName);
        if (flag == 1) {
            String path = downloading();
            fileProgressbar = new ProgressBar(fileName,fileSize,"Downloading");
            fileProgressbar.setVisible(true);
            try {
                out = new BufferedOutputStream(new FileOutputStream(path+""+exe));
                return true;
            } catch (FileNotFoundException ex) {
                System.out.println("Can't Open the file");
            }
            return false;

        }
        
        return false;
    }

    @Override
    public void closeStream(String filename) throws RemoteException {
        try {
            out.close();
            JOptionPane.showMessageDialog(null, "Downloaded Complete - file '"+ filename+"'");
            fileProgressbar.setVisible(false);
            fileProgressbar = null;
            out = null;
        } catch (IOException ex) {
            System.out.println("Error during closing the file stream");
        }
    }
    
    public int receiveFile(String fileName, String friendName)  {

        int reply = JOptionPane.showConfirmDialog(null, "Do you want to save from your friend '"+friendName+"' the file '"+fileName+"'", "", JOptionPane.YES_NO_CANCEL_OPTION);

        if (reply == 0) {
            return 1;
        }
        return 0;
       
    }

    public String downloading() throws RemoteException {
        fd = new FileDownload();
        fd.setVisible(true);
        int flag = fd.fileFlag();
        if (flag == 1) {

            String path = fd.pathReturn();
            return path;
        }
        return null;
    }

    
    @Override
    public void receive(byte[] b) throws RemoteException {

        try {
            out.write(b);
            out.flush();
            fileProgressbar.incrementSize();

        } catch (IOException ex) {
            System.out.println("Error during receiving file bytes");
        }

    }

    class SendFileListener extends MouseAdapter {
        
        @Override
        public void mouseClicked(MouseEvent e) {
            System.out.println("Hi");
            try {
                file = new FileUpload();
            } catch (IOException ex) {
                System.out.println("Can't View Files and Directories");
            }
            file.setVisible(true);
            int flag = file.returnFlag();
            if (flag == 1) {
                f = file.returnFile();                  
                try {
                    in = new BufferedInputStream(new FileInputStream(f));
                } catch (FileNotFoundException ex) {
                    System.out.println("Can't BufferInput");
                }

                final ChatWindow cw = (ChatWindow) SwingUtilities.getRoot((Component) e.getSource());

                th = new Thread(new Runnable() {

                    @Override
                    public void run() {

                        
                        byte[] data = new byte[4000];

                        ClientInt friend = allclients.get(cw.getFriendUserName());
                        
                        try {
                            File temp = new File(f);
                            f = f.substring(f.lastIndexOf("/")+1,f.length());
                            ProgressBar pb = new ProgressBar(f, (int) temp.length(),"Uploading");
                            pb.setVisible(true);
                            boolean start = friend.startStream(f, (int) temp.length(),myUser.getUserName());
                            
                            if(start){                             
                            
                                while (in.read(data) != -1) {
                                    friend.receive(data);
                                    pb.incrementSize();
                                }
                            
                                friend.closeStream(f);
                                in.close();
                                pb.setVisible(false);
                                JOptionPane.showMessageDialog(null, "File Uploaded Done! - file "+f);
                            }else{
                                JOptionPane.showMessageDialog(null, "Error During Uploading File "+f);
                                pb.setVisible(false);
                                pb = null;
                            }                       
                               
                        } catch (IOException ex) {
                            System.out.println("Can't Open or send the File");
                        }
                    }
                });
                th.start();
            }
        }
    }
    
    @Override
    public void sendInteractive(String msg,String username) throws RemoteException {
        //System.out.println(chatWindow.containsKey(username));
        if(chatWindow.containsKey(username)){
            chatWindow.get(username).setInteractiveMsgField(msg);
        }
        
    }
    
    class AddInteractiveChatListener implements CaretListener
    {
         
        

        
        public void caretUpdate(CaretEvent e) {
           ChatWindow cw = (ChatWindow) SwingUtilities.getRoot((Component) e.getSource());
            String friend=cw.getFriendUserName();

            User friendObj = ClientImpl.this.getUserObj(friend);
            if(friendObj.status() == 0 || friendObj.status() == 4 ){
                JOptionPane.showMessageDialog(null, "Your Friend Is Offline Now !!");
                return;
            }
            
            
            try {
                //cw.setText2(x);
               // System.out.println(cw.getMsgToSend());
                if(allclients.containsKey(friend))
                    allclients.get(friend).sendInteractive(cw.getMsgToSend(), myUser.getUserName());
            } catch (RemoteException ex) {
                System.out.println("Can't Send The Client Interactive messages");
            }
        }
    }
    
    @Override
    public void receiveAd(String msg) throws RemoteException {
        contactList.setAdv(msg);
    }
    
    @Override
    public void shutdown() throws RemoteException {

        if(contactList != null){    contactList.setVisible(false); contactList = null; }
        if(addFriend != null){      addFriend.setVisible(false);     addFriend = null;     }
        if(addPeople != null){      addPeople.setVisible(false);   addPeople = null;   }
        if(signIn != null){         signIn.setVisible(true);      }
        if(signUp != null){         signUp.setVisible(false);      signUp = null;      }
        if(sendMail != null){       sendMail.setVisible(false);    sendMail = null;    }
            
        for (Map.Entry<String, ChatWindow> entry : chatWindow.entrySet()) {
            entry.getValue().setVisible(false);
        }
        
        chatWindow.clear();
            
        for (Map.Entry<Integer, ChatWindow> entry : chatConference.entrySet()) {
            entry.getValue().setVisible(false);
        }
        
        chatConference.clear();
                        
            
        allclients.clear();
        conference.clear();
        myUser = null;
        friends = null;
        server = null;
        System.gc();
    }

    
}
